package com.javaex.book.web;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.javaex.book.utils.LoggerUtils;
import com.javaex.book.utils.RequestMethod;

/**
 * Controller中每个方法与请求url的映射关系
 *
 * @author 黄星琦
 * @Date 2022年3月2日
 */
public class Handler {

	private static final Logger logger = LoggerFactory.getLogger(Handler.class);
	
	/** Controller中的业务方法 */
	private Method method;
	
	/** 匹配的url */
	private String urlPattern;
	
	/** 请求类型 */
	private RequestMethod requestMethod;
	
	/** Controller类实例，用于invoke执行业务方法 */
	private Object instance;
	
	public Handler(Method method, String urlPattern, RequestMethod requestMethod, Object instance) {
		this.method = method;
		this.urlPattern = urlPattern;
		this.requestMethod = requestMethod;
		this.instance = instance;
	}
	
	/**
	 * 执行业务方法
	 * @param req
	 * @param resp
	 * @return 业务方法执行结果
	 */
	public Object execute(HttpServletRequest req, HttpServletResponse resp) {
		Object[] params = getMethodParams(req, resp);
		try {
			return method.invoke(instance, params);
		} catch (Exception e) {
			logger.error("{}.{}方法执行失败\n方法参数：{}\n{}", instance.getClass().getSimpleName(), method.getName(), params, LoggerUtils.format(e, "com.javaex.book"));
			throw new RuntimeException(e);
		} 
	}
	
	/**
	 * 获取方法反射执行的参数
	 * @param req
	 * @param resp 
	 * @return 方法参数数组
	 */
	private Object[] getMethodParams(HttpServletRequest req, HttpServletResponse resp) {
		Parameter[] parameters = method.getParameters();
		if (parameters.length == 0) {
			return null;
		}
		List<Object> list = new ArrayList<Object>(); 
		for (Parameter parameter : parameters) {
			if (parameter.getType() == HttpServletRequest.class) {
				list.add(req);
				continue;
			} 
			if (parameter.getType() == HttpServletResponse.class) {
				list.add(resp);
				continue;
			} 
			if (parameter.getType() == HttpSession.class) {
				list.add(req.getSession());
				continue;
			}
			if (parameter.getType() == Cookie[].class) {
				list.add(req.getCookies());
				continue;
			} 
			list.add(null);
		}
		return list.toArray();
	}

	public Method getMethod() {
		return method;
	}

	public String getUrlPattern() {
		return urlPattern;
	}

	public RequestMethod getRequestMethod() {
		return requestMethod;
	}
	
	public Object getInstance() {
		return instance;
	}
}
